home *** CD-ROM | disk | FTP | other *** search
- Path: news.th-darmstadt.de!news
- From: Enno Sandner <enno@intellektik.informatik.th-darmstadt.de>
- Newsgroups: comp.lang.c++
- Subject: Re: Here is my idea of callback code. However there are glitches can it be done better.
- Date: Thu, 18 Apr 1996 15:56:34 +0200
- Organization: Fachbereich Informatik, TH Darmstadt
- Message-ID: <31764A12.1CFBAE39@intellektik.informatik.th-darmstadt.de>
- References: <Pine.SUN.3.91N2x.960418124921.4515B-100000@mumrik.nada.kth.se>
- NNTP-Posting-Host: kitz.intellektik.informatik.th-darmstadt.de
- Mime-Version: 1.0
- Content-Type: text/plain; charset=iso-8859-1
- Content-Transfer-Encoding: 8bit
- X-Mailer: Mozilla 2.01 (X11; I; SunOS 4.1.3 sun4m)
-
- Fredrik ╓hrstr÷m wrote:
- >
- > How do people write callbacks? The following code captures what I want
- > of callbacks.
- > * Callbacks call class functions.
- > * The calling object does not need to know what object, what function,
- > what callback it is calling. It knows that it calls a TutCallback f.ex.
- > but if the user wants to subclass the TutCallback to insert more
- > information at callback time thats completely ok.
- > * It is easy to create new callbacks. (Before I hade to create two classes
- > for each new callback.)
- > However there are some negative things.
- > * It is a pointer to pointer to function thingi.
- > * The compiler warns >>Contravariance violation<<
- > Because I cast b = void (Test::*)(TutCallback*)
- > to void (Test::*)(Callback*)
- > And I do not know how to stop this from happening.
- >
- > Is there anyone out there that has a better way of calling callbacks?
- > Or if somebody knows how to fix this I would be very happy!
- >
- > Here's the code. (Just the essential stuff, no memchecking and so on.)
- >
- > #include <iostream.h>
- >
- > struct Caller;
- > template<class T> struct Call;
- > struct Callback;
- >
- > struct Caller
- > {
- > virtual void call (Callback *cb) { }
- > };
- >
- > template<class T>
- > struct Call : public Caller
- > {
- > typedef void (T::*FuncPtr)(Callback *);
- >
- > Call (T *o, FuncPtr f) : object_(o), function_(FuncPtr(f)) { }
- >
- > void call (Callback *cb) { (object_->*function_) (cb); }
- >
- > T *object_;
- > FuncPtr function_;
- > };
- >
- > struct Callback
- > {
- > Callback (Caller *caller) : caller_ (caller) { }
- > virtual void invoke () { caller_->call (this); }
- >
- > Caller *caller_;
- > };
- >
- > // This is an easy way to create new Callbacks I think!
- >
- > struct TutCallback : public Callback
- > {
- > TutCallback (Caller *c, int u) : Callback (c), tut (u) { }
- >
- > int tut;
- > };
- >
- > struct Test
- > {
- > TutCallback *cb;
- >
- > Test ()
- > {
- > cb = new TutCallback (new Call<Test>(this,b), 5);
- > cb->invoke ();
- > }
- >
- > void b (TutCallback *cb)
- > {
- > cerr << "Tut! " << cb->tut << endl;
- > }
- > };
- >
- > int main ()
- > {
- > Test test;
- > }
-
- Basically your idea is ok (check out the 'Command Pattern' in the Design
- Patterns book for a more general approach).
- To remove the problems you can make 'Caller' a generic class that takes
- the type of the argument of the 'call' function:
-
- template<class Arg> class Caller {
- public:
- virtual ~Caller() {}
- virtual void call(Arg a)=0;
- };
-
- The resulting subclass 'Call' becomes generic with two arguments.
-
- template<class T,class Arg> class Call : public Caller<Arg> { ... };
-
- This and the appropriate modifications allows you to write:
-
- cb = new TutCallback (new Call<Test,TutCallback*>(this,b), 5);
-
- in Test's constructor without any problems.
-
- Enno
-